﻿using System;
using System.Reflection;

namespace Tszy.Unlimited.Base.Objects.Methods
{
    internal class MethodWarpper
    {
        #region 0个参数

        public static IExecuteMethod0 GetMethodWrapper(string methodName, Type targetType)
        {
            var method = targetType.GetMethod(methodName);

            return CreatePropertySetterWrapper(method);
        }

        private static IExecuteMethod0 CreatePropertySetterWrapper(MethodInfo method)
        {
            if (method == null)
                return null;

            if (method.GetParameters().Length > 1)
                throw new NotSupportedException("不支持构造索引器属性的委托。");

            var instanceType = typeof(ExecuteMethodWrapper<>).MakeGenericType(method.DeclaringType);
            return (IExecuteMethod0)Activator.CreateInstance(instanceType, method);
        }

        #endregion 0个参数

        #region 1个参数

        public static IExecuteMethod1 GetMethodWrapper(string methodName, Type targetType, Type parameterType)
        {
            var method = targetType.GetMethod(
                methodName,
                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
                null,
                new[] { parameterType },
                null);

            return CreatePropertySetterWrapper(method, parameterType);
        }

        private static IExecuteMethod1 CreatePropertySetterWrapper(MethodInfo method, Type parameterType)
        {
            if (method == null)
                return null;

            if (method.GetParameters().Length > 1)
                throw new NotSupportedException("不支持构造索引器属性的委托。");

            var instanceType = typeof(ExecuteMethodWrapper<,>).MakeGenericType(method.DeclaringType, parameterType);
            return (IExecuteMethod1)Activator.CreateInstance(instanceType, method);
        }

        #endregion 1个参数

        #region 2个参数

        public static IExecuteMethod2 GetMethodWrapper(string methodName, Type targetType, Type parameterType1, Type parameterType2)
        {
            var method = targetType.GetMethod(
                methodName,
                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
                null,
                new[] { parameterType1, parameterType2 },
                null);

            return CreatePropertySetterWrapper(method, parameterType1, parameterType2);
        }

        private static IExecuteMethod2 CreatePropertySetterWrapper(MethodInfo method, Type parameterType1, Type parameterType2)
        {
            if (method == null)
                return null;

            if (method.GetParameters().Length != 2)
                throw new NotSupportedException("不支持构造索引器属性的委托。");

            var instanceType = typeof(ExecuteMethodWrapper2<,,>).MakeGenericType(method.DeclaringType, parameterType1, parameterType2);
            return (IExecuteMethod2)Activator.CreateInstance(instanceType, method);
        }

        #endregion 2个参数
    }

    #region 0个参数

    internal interface IExecuteMethod0
    {
        void Execute(object target);
    }

    internal class ExecuteMethodWrapper<TTarget> : IExecuteMethod0
    {
        private readonly Action<TTarget> _methodInvoke;

        public ExecuteMethodWrapper(MethodInfo method)
        {
            _methodInvoke = (Action<TTarget>)Delegate.CreateDelegate(typeof(Action<TTarget>), null, method);
        }

        public void Execute(object target)
        {
            _methodInvoke((TTarget)target);
        }
    }

    #endregion 0个参数

    #region 1个参数

    internal interface IExecuteMethod1
    {
        void Execute(object target, object val);
    }

    internal class ExecuteMethodWrapper<TTarget, TValue> : IExecuteMethod1
    {
        private readonly Action<TTarget, TValue> _methodInvoke;

        public ExecuteMethodWrapper(MethodInfo method)
        {
            _methodInvoke = (Action<TTarget, TValue>)Delegate.CreateDelegate(typeof(Action<TTarget, TValue>), null, method);
        }

        public void Execute(object target, object val)
        {
            _methodInvoke((TTarget)target, (TValue)val);
        }
    }

    #endregion 1个参数

    #region 2个参数

    internal interface IExecuteMethod2
    {
        void Execute(object target, object val1, object val2);
    }

    internal class ExecuteMethodWrapper2<TTarget, TValue1, TValue2> : IExecuteMethod2
    {
        private readonly Action<TTarget, TValue1, TValue2> _methodInvoke;

        public ExecuteMethodWrapper2(MethodInfo method)
        {
            _methodInvoke = (Action<TTarget, TValue1, TValue2>)Delegate.CreateDelegate(typeof(Action<TTarget, TValue1, TValue2>), null, method);
        }

        public void Execute(object target, object val1, object val2)
        {
            _methodInvoke((TTarget)target, (TValue1)val1, (TValue2)val2);
        }
    }

    #endregion 2个参数
}